1183 tokens in Rust for part 1 by Mechazawa
Download solution
usestd::fmt::Display
usestd::io::{stdin,Read}
constMAPPED_CHAR:char='.'
#[derive(Clone,Copy,Debug,Eq,Hash,PartialEq,PartialOrd)]
structPoint(usize,usize)
implPoint{
pubfnneighbours(&self)->Vec<Point>{
vec![
Point(self.0.wrapping_sub(1),self.1),
Point(self.0,self.1.wrapping_sub(1)),
Point(self.0.saturating_add(1),self.1),
Point(self.0,self.1.saturating_add(1)),
]
}
}
#[derive(Debug)]
structGrid{
rows:usize,
cols:usize,
data:Vec<char>,
}
implGrid{
pubfnfrom_str(data:&str)->Self{
letrows=data.lines().count()
letcols=data.lines().next().map_or(0,|line|line.chars().count())
letdata=data.lines().flat_map(|line|line.chars()).collect()
Self{rows,cols,data}
}
pubfnget(&self,point:Point)->Option<char>{
ifpoint.0<self.rows&&point.1<self.cols{
Some(self.data[point.0*self.cols+point.1])
}else{
None
}
}
pubfnset(&mutself,point:Point,value:char){
ifpoint.0<self.rows&&point.1<self.cols{
self.data[point.0*self.cols+point.1]=value
}
}
pubfnfind_unmapped(&self)->Option<Point>{
forrowin0..self.rows{
forcolin0..self.cols{
letpoint=Point(row,col)
ifself.get(point).unwrap()!=MAPPED_CHAR{
returnSome(point)
}
}
}
None
}
pubfnget_region(&self,start:Point)->Option<Region>{
letmutregion=Region::new(self.get(start)?)
letmutstack=vec![start]
whileletSome(point)=stack.pop(){
ifletSome(c)=self.get(point){
ifc==region.name&&!region.points.contains(&point){
stack.extend(point.neighbours())
region.points.push(point)
}
}
}
Some(region)
}
pubfntake_region(&mutself,start:Point)->Option<Region>{
letregion=self.get_region(start)?
region
.points
.iter()
.for_each(|point|self.set(*point,MAPPED_CHAR))
Some(region)
}
}
implDisplayforGrid{
fnfmt(&self,f:&mutstd::fmt::Formatter<'_>)->std::fmt::Result{
forrowin0..self.rows{
forcolin0..self.cols{
write!(f,"{}",self.get(Point(row,col)).unwrap())?
}
writeln!(f)?
}
Ok(())
}
}
#[derive(Debug)]
structRegion{
name:char,
points:Vec<Point>,
}
implRegion{
pubfnnew(name:char)->Self{
Self{
name,
points:Vec::new(),
}
}
pubfnarea(&self)->usize{
self.points.len()
}
pubfnperimeter(&self)->usize{
letmutperimeter=0
forpointin&self.points{
letmutneighbours=0
forneighbourinpoint.neighbours(){
ifself.points.contains(&neighbour){
neighbours+=1
}
}
perimeter+=4-neighbours
}
perimeter
}
fnbottom_right(&self)->Point{
letmax_row=self.points.iter().map(|p|p.0).max().unwrap()
letmax_col=self.points.iter().map(|p|p.1).max().unwrap()
Point(max_row,max_col)
}
pubfnsides(&self)->usize{
letmuttotal_sides=0
letbottom_right=self.bottom_right()
constLEFT:usize=1
constRIGHT:usize=3
fordirectionin0..4{
letmutvisited=vec![]
forpointin&self.points{
ifvisited.contains(point)||self.points.contains(&point.neighbours()[direction]){
continue
}
total_sides+=1
visited.push(*point)
forsidein&[LEFT,RIGHT]{
letmutcurrent=point.clone()
whilecurrent<=bottom_right
&&self.points.contains(¤t)
&&!self.points.contains(¤t.neighbours()[direction])
{
visited.push(current)
current=current.neighbours()[(direction+side)%4]
}
}
}
}
total_sides
}
}
fnmain(){
letmutinput=String::new()
stdin().lock().read_to_string(&mutinput).unwrap()
letmutgrid=Grid::from_str(&input)
letmutpart1=0
letmutpart2=0
whileletSome(point)=grid.find_unmapped(){
letregion=grid.take_region(point).unwrap()
part1+=region.area()*region.perimeter()
part2+=region.area()*region.sides()
}
println!("{}",part1)
}