Mercurial > repos > icfp2014
changeset 37:e613d243d2bc
Merge
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Sat, 26 Jul 2014 03:18:17 -0700 |
parents | c0b3922646d8 (diff) c68c03a0e072 (current diff) |
children | 6b9b21456cf4 |
files | |
diffstat | 2 files changed, 170 insertions(+), 1 deletions(-) [+] |
line wrap: on
line diff
--- a/code/README Sat Jul 26 02:32:59 2014 -0700 +++ b/code/README Sat Jul 26 03:18:17 2014 -0700 @@ -0,0 +1,119 @@ +Team: Rhope Burn +Language: Quiche +Members: Michael Pavone, William Morgan + +HOW TO BUILD: + +To build our Lambda-man AI, you first need to build the lmc compiler. lmc is +written in a WIP language called Quiche. The steps to get a Quiche toolchain +setup are as follows: + +1) Make a local clone of hg repo: http://rhope.retrodev.com/repos/tabletprog +2) Make sure the d8 Javascript shell (built from Chrome's v8) is in your path + -- see this page for instructions on how to build d8: + https://developers.google.com/v8/build +3) Install the Boehm GC development package (libgc-dev on Debian derivatives) +3) Install gcc if it is not already present + +Once you have the toolchain in place, navigate to the Quiche repo clone in a +terminal and execute the following command. + +./compile PATH/TO/lmc.tp + +If all goes well an executable named lmc will be produced at PATH/TO/lmc. This +program takes a .lm file as an argument and produces "GCC" assembly code on +stdout. + +ABOUTE QUICHE: + +Quiche (previously called TP) is a language I (Michael Pavone) work on in my +spare time. It draws rather heavily from Smalltalk with a smattering of +influence from other languages. In theory, it's reason for existence is to be +a good target for a structured editor on mobile devices. In practice, I'd +probably be better served targeting an existing language, but that's not nearly +as much fun. + +The current implementation is a quick and dirty bootstrap compiler written in +Javascript that produces C code. A self-hosted compiler is in progress. + +A Quiche program is made up of one or more modules. At runtime, a module is +just a plain object. Only one module is allowed per source file. The top level +of a Quiche source file is required to either be an object literal or a lambda +that returns an object. After all modules used are initialized, execution +starts in the main method of the main module. Currently, the names of all +available modules occupy the top level of the symbol table; however, this will +change in the self-hosted compiler. + +QUICHE SYNTAX: + +To make reading lmc's code a bit easier, here is a quick primer on Quiche's +syntax. + +line comment: // +block comment: /* */ +assignment: foo <- bar +list literal: [1 2 3 4] +array literal: #[1 2 3 4] +string literal "foo bar" +lambda: :arg { + arg + 1 +} +object literal: #{ + foo <- "blah blah" + bar <- :val { + foo <- val . " blah" + } +} +method invokation/function application: + someval someFunOrMeth + someFunOrMeth: someval + some: val1 Fun: val2 OrMeth: val3 + some:Fun:OrMeth: val1 val2 val3 +operators: + +,-,/,* -- basic arithmetic + =,!=,>=,<= -- comparison + and,or,xor -- bitwise + % -- modulus + . -- concatenation + | -- cons + +ABOUT LMC: + +lmc implements a subset of Quiche for the LamCo General Compute Coprocessor. It +uses the parser, ast and symbols modules from the work in progress self-hosted +compiler. Object literals are not supported apart from the top-level object +that represents the module. That object is used to populate the global +environment. Closures are properly supported; however, some elements that are +implemented using closures in the normal Quiche compiler (namely if:else and +while:do) are instead implemented as special forms that do not introduce a new +scope. Array literals are used for producing tuples as the GCC does not really +support the former and Quiche does not currently support the latter. + +Tail call optimization is notcurrently implemented; however, while:do is +implemented using TSEL so we were able to do without. + +LIGHTNING ROUND SOLUTION: + +Our lightning round solution is relatively simple. Each step, we do a breadth +first search for something desirable (pellet, power pellet, fruit or fright +mode ghost). Cells occupied by normal mode ghosts and their immediate neighbors +are marked as walls to provide simple avoidance behavior. + +We translate the grid to a tree format to provide more efficient lookup. An +identically dimensioned tree is used for keeping track of visited nodes for our +search. + +This seems to work surprisingly well given how simple it is. I'm a bit +concerned about our cycle usage when the nearest "good" thing is far away, +hopefully that will not be an issue. + +We noticed that the "undefined" input to main appears to be the ghost code, but +we did not have time to take advantage of it for the lightning round. + +The code for this AI is located in dotScanner.lm + +OTHER FILES: + +test.lm - random collection of syntax for exercising parts of the compiler +simple.lm - picks each direction in order every 4 turns +mike00.lm - test program for developing library functions
--- a/code/dotScanner.lm Sat Jul 26 02:32:59 2014 -0700 +++ b/code/dotScanner.lm Sat Jul 26 03:18:17 2014 -0700 @@ -260,10 +260,12 @@ } else: { atpos <- grid: grid get: myLoc if: (atpos = 2) + (atpos = 3) + (atpos = 4) { + //pellet, power pellet, fruit ret <- #[1 (reverse: path)] } else: { visited <- grid: visited set: myLoc to: 1 if: atpos { + //empty space move <- 0 while: { move < 4 } do: { ret <- (makeContClos: grid (calcPos: move myLoc) move | path) | ret @@ -280,28 +282,76 @@ } step <- :myState world { - grid <- makeTree: (map: (world value) :row { makeTree: row }) lmState <- (world tail) value myLoc <- (lmState tail) value + ghostState <- ((world tail) tail) value + fruitState <- ((world tail) tail) tail + grid <- makeTree: (map: (world value) :row { + if: fruitState >= 127 { + } else: { + row <- map: row :el { + //remove fruit if it is not enabled + if: el = 4 { + el <- 1 + } else: {} + el + } + } + makeTree: row + }) + grid <- fold: ghostState grid with: :acc ghost { + vitality <- ghost value + loc <- (ghost tail) value + dir <- (ghost tail) tail + nextloc <- 0 + move <- 0 + if: vitality = 1 { + //treat fright mode ghosts as a pellet for now + acc <- grid: acc set: loc to: 2 + } else: { + if: vitality = 0 { + //treat normal mode ghosts as a wall for now + acc <- grid: acc set: loc to: 0 + while: { move < 4 } do: { + nextloc <- calcPos: move loc + if: (grid: acc inBounds?: nextloc) { + acc <- grid: acc set: nextloc to: 0 + } else: {} + move <- move + 1 + } + } else: {} + } + acc + } + //make sure my location is marked clear even if there is a ghost nearby + grid <- grid: grid set: myLoc to: 1 visited <- treeMap: grid :row { treeMap: row :el { 0 } } path <- advancer: [(makeContClos: grid myLoc [])] + if: (path isInteger?) { + print: 42 + path <- [0] + } else: {} #[0 (path value)] } main <- :initWorld ghostCode { /* print: (step: 0 #[ + //grid [ [0 0 0 0] [0 2 2 0] [0 1 0 0] [0 0 0 0] ] + //lmstate #[0 #[1 2] 2 3 0] + //ghost state [] + //fruit state 0 ]) */ #[0 step]